<?php
/**
 * DVelum project http://code.google.com/p/phpveil/ , http://dvelum.net
 * Copyright (C) 2011  Kirill A Egorov kirill.a.egorov@gmail.com
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Background task abstract class
 * @package Bgtask
 */
abstract class Bgtask_Abstract
{
    const SIGNAL_SLEEP = 1;
    const SIGNAL_CONTINUE = 2;
    const SIGNAL_STOP = 3;
    
    const STATUS_UNDEFINED = 0;
    const STATUS_RUN = 1;
    const STATUS_SLEEP = 2;
    const STATUS_STOPED = 3;
    const STATUS_FINISHED = 4;
    
    protected $_logger = null;
    /**
     * Task PID
     * @var integer
     */
    protected $_pid;
    /**
     * Sleep state
     * @var boolean
     */
    protected $_sleepFlag = false;
    /**
     * Sleep interval in seconds
     * @var integer
     */
    protected $_sleepInterval = 3;
    /**
     * Operation count
     * @var integer
     */
    protected $_opTotal = 0;
    /**
     * Finished operations
     * @var integer
     */
    protected $_opFinished = 0;
    /**
     * Status
     * @var integer
     */
    protected $_status = 0;
    /**
	 * Task config
	 * @var array
	 */
	protected $_config;   
	/**
	 * @var Bgtask_Manager
	 */
	protected $_tm;
    /**
     * @param array $config
     */
    public function __construct(array $config){
    	$this->_config = $config;
    	$this->_tm = Bgtask_Manager::getInstance();
        $this->_logger = $this->_tm->getLogger();
        $this->_init();
        $this->run();
    }
    /**
     * Get task deskription
     * @return string
     */
    abstract public function getDescription();
    
    protected  function _init()
    { 	
    	$this->_pid = $this->_tm->addTaskRecord($this->getDescription());
    	$this->_status = self::STATUS_RUN;
    	$this->_tm->setStarted($this->_pid); 	
    	if(!is_null($this->_logger))
    		$this->_logger->log('start');
    }
    /**
     * Check if task was killed by task manager
     */
    protected function _isLive(){
    	if(!$this->_tm->isLive($this->_pid))
    		$this->terminate();
    }
    /**
     * Sleep
     */
    protected function _sleep(){
    	$this->_status = self::STATUS_SLEEP;
    	$this->_sleepFlag = true;
    	$this->updateState();	
    	if(!is_null($this->_logger))
    		$this->_logger->log('sleep');
    }
    /**
     * Continue
     */
    protected function _continue(){
    	$this->_sleepFlag = false;
    	$this->_status = self::STATUS_RUN;
    	$this->updateState();	
    	if(!is_null($this->_logger))
    		$this->_logger->log('continue');
    }
    /**
     * Terminate
     */
    public function terminate(){
    	if(!is_null($this->_logger))
    		$this->_logger->log('terminated');
    	exit();	
    }
    
    /**
     * Finish task
     */
    public function finish(){
    	$this->updateState();
    	
    	$manager = $this->_tm;
    	$manager->setFinished($this->_pid);
    	$manager->clearSignals($this->_pid);
    	
    	if(!is_null($this->_logger))
    		$this->_logger->log('finish');
    	   
    	exit();	
    }
    /**
     * Stop task
     */
    public function stop(){
    	$this->_sleepFlag = false;
    	$this->updateState();
    	$this->_tm->setStoped($this->_pid);
    	$this->_tm->clearSignals($this->_pid);
    	
    	if(!is_null($this->_logger))
    		$this->_logger->log('stop');
    		
    	exit();	
    }
    /**
     * Update status info
     * @return void
     */
    public function updateState(){
    	$this->_tm->updateState($this->_pid, $this->_opTotal , $this->_opFinished, $this->_status);
    }
    /**
     * Process signals
     */
    public function processSignals()
    {
    	$this->_isLive();
    	
        $sig = $this->_tm->getSignals($this->_pid , true);
        
        if(empty($sig))
            return;
            
        foreach ($sig as $signal){
            switch ($signal){
                case self::SIGNAL_SLEEP : $this->_sleep();
                    break;
                case self::SIGNAL_CONTINUE : $this->_continue();
                    break;
                case self::SIGNAL_STOP: $this->stop();
            }
        }  
        if($this->_sleepFlag)
        	$this->_wait();
    }
    /**
     * Wait for signals
     */
    protected function _wait()
    {    
        while ($this->_sleepFlag){
            sleep($this->_sleepInterval);
            $this->processSignals();
        }
    }
    
    abstract public function run();

    /**
     * Set logger
     * @param Bgtask_Log $logger
     * @return void
     */
    public function setLogger(Bgtask_Log $logger){
    	$this->_logger = $logger;
    }
    /**
     * Set total count of expected operations
     * @param integer $count
     */
    public function setTotalCount($count){
    	$this->_opTotal = $count;
    }
    /**
     * Set count of completed operations
     * @param integer $count
     */
    public function setCompletedCount($count){
    	$this->_opFinished = $count;
    }
    /**
     * Increment complited operations counter
     */
    public function incrementCompleted(){
    	$this->_opFinished ++;
    }
}